/*
 * Copyright (c) 2009 LastFM.Desktop Anton Pavlik.
 * All Rights Reserved.
 * 
 * You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, 
 * with or without modifications, and in Source or Object form, provided that You meet the following 
 * conditions:
 * 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
 *
 * 2. You must cause any modified files to carry prominent notices stating that You changed the files; 
 * and
 *
 * 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, 
 * patent, trademark, and attribution notices from the Source form of the Work, excluding those notices 
 * that do not pertain to any part of the Derivative Works.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * You may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, Licensor provides the Work 
 * (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
 * CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties 
 * or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 
 * YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE WORK
 * AND ASSUME ANY RISKS ASSOCIATED WITH YOUR EXERCISE OF PERMISSIONS UNDER THIS LICENSE. 
 */
package org.shake.lastfm.ui.playlist;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.annotation.EventTopicSubscriber;
import org.shake.lastfm.event.CaptureTrackRequestEvent;
import org.shake.lastfm.event.EventTopic;
import org.shake.lastfm.event.FetchPlaylistRequestEvent;
import org.shake.lastfm.event.SessionStartedEvent;
import org.shake.lastfm.event.TrackCapturedEvent;
import org.shake.lastfm.model.Playlist;
import org.shake.lastfm.model.Track;
import org.shake.lastfm.model.TrackStatus;
import org.shake.lastfm.net.LastFmCommunicator;
import org.shake.lastfm.swing.SwingJob;
import org.shake.lastfm.ui.controller.PlaylistController;

public class TracksHandler
{
    private Log log = LogFactory.getLog(TracksHandler.class);
    private final TrackListModel trackModel;
    
    private PlaylistController plController;
    
    public TracksHandler(TrackListModel trackModel)
    {
        this.trackModel = trackModel;
        this.plController = new PlaylistController();
    }
    
    @EventTopicSubscriber(topic = EventTopic.SESSION_STARTED_EVENT)
    public void onSessionStarted(String topic, SessionStartedEvent event)
    {
        EventBus.publish(EventTopic.PLAYLIST_FETCH_REQUEST, new FetchPlaylistRequestEvent(event.isStartCapturing()));
    }
    
    @EventTopicSubscriber(topic = EventTopic.PLAYLIST_FETCH_REQUEST)
    public void onFetchPlaylistRequest(String topic, FetchPlaylistRequestEvent event)
    {
        this.plController.fetchPlaylist(new UpdatePlaylistJob(event.isStartCapturing()));
    }
    
    @EventTopicSubscriber(topic = EventTopic.TRACK_CAPTURE_REQUEST)
    public void onCaptureTrackRequest(String topic, CaptureTrackRequestEvent event)
    {
        Track track = event.getTrack();
        if (event.isStartFromTheTop())
        {
            track = this.trackModel.nextScheduledTrack();
        }

        if (track != null)
        {
            log.info("Track capture request " + track);

            CaptureTrackJob captureTrackJob = new CaptureTrackJob(track);
            this.trackModel.setTrackStatus(track, TrackStatus.IN_PROGRESS);
            this.plController.captureTrack(captureTrackJob);
        } else
        {
            // no tracks found; try to fetch playlist
            EventBus.publish(EventTopic.PLAYLIST_FETCH_REQUEST, new FetchPlaylistRequestEvent(true));
        }
    }
    
    @EventTopicSubscriber(topic = EventTopic.TRACK_CAPTURE_DONE)
    public void onTrackCaptured(String topic, TrackCapturedEvent event)
    {
        Track scheduledTrack = this.trackModel.nextScheduledTrack();
        
        if (scheduledTrack == null)
        {
            EventBus.publish(EventTopic.PLAYLIST_FETCH_REQUEST, new FetchPlaylistRequestEvent(true));
        }
        else
        {
            EventBus.publish(EventTopic.TRACK_CAPTURE_REQUEST, new CaptureTrackRequestEvent(scheduledTrack));
        }
    }
    
    private class UpdatePlaylistJob implements SwingJob<Playlist>
    {
        private final boolean startCapturing;

        public UpdatePlaylistJob(boolean startCapturing)
        {
            this.startCapturing = startCapturing;
        }

        @Override
        public void onJobDone(Playlist data)
        {
            if (data != null)
            {
                TracksHandler.this.trackModel.appendTracks(data.getTracks());
                if (this.startCapturing)
                {
                    Track scheduledTrack = TracksHandler.this.trackModel.nextScheduledTrack();
                    if (scheduledTrack != null)
                    {
                        log.info("sending " + EventTopic.TRACK_CAPTURE_REQUEST);
                        EventBus.publish(EventTopic.TRACK_CAPTURE_REQUEST, new CaptureTrackRequestEvent(scheduledTrack));
                    }
                    else
                    {
                        log.info("no tracks to capture");
                    }
                }
            } else
            {
                /* session expired? */
//                LastFmCommunicator.getInstance().startSessionIfNeeded(true);
            }
        }

        @Override
        public Playlist readUI()
        {
            return null;
        }

        @Override
        public void onJobCanceled(Exception ex)
        {
            log.error(ex);
            if (ex instanceof IllegalStateException)
            {
                LastFmCommunicator.getInstance().startSessionIfNeeded(true);
            }
        }
    }
    
    private class CaptureTrackJob implements SwingJob<Track>
    {
        private final Track trackToCapture;

        public CaptureTrackJob(Track trackToCapture)
        {
            this.trackToCapture = trackToCapture;
        }

        @Override
        public Track readUI()
        {
            return this.trackToCapture;
        }

        @Override
        public void onJobDone(Track track)
        {
            TracksHandler.this.trackModel.setTrackStatus(track, TrackStatus.ON_DISK);
            EventBus.publish(EventTopic.TRACK_CAPTURE_DONE, new TrackCapturedEvent(track));
        }

        @Override
        public void onJobCanceled(Exception ex)
        {
            /* capturing failed */
            log.error("Capturing failed : " + this.trackToCapture, ex);
            /* mark the track as FAILED */
            TracksHandler.this.trackModel.setTrackStatus(this.trackToCapture, TrackStatus.FAILED);
            EventBus.publish(EventTopic.TRACK_CAPTURE_DONE, new TrackCapturedEvent(this.trackToCapture));
        }
    }

}